#include "raid.h"
#include <stdint.h>

int32_t hilo_crear() {
	int32_t vRetorno;
	vRetorno=pthread_create(&hilito, NULL, hilo_Funcion, NULL);
	if (vRetorno) {
		printf("ERROR; return code from pthread_create() is %d\n", vRetorno);
		exit(-1);
	}
	return vRetorno;
}
void *hilo_Funcion(void) {
	//variables de hilo

	//variables de las lsitas del select
	struct listaSelect *punteroAuxSelect=NULL;
	//variables de NIPC
	struct nipc_protocol punteroNIPCRecibir;
	//variables de sockets/select
	fd_set conjuntoDeDescriptores;
	int32_t maximo;
	int32_t C;
	int32_t H;
	int32_t S;
	int32_t cabezal=0;
	int32_t cilindros=0;
	int32_t sectoresPorPista=0;
	int32_t descriptorElegido;
	//variables de listas a escribir/leer
	struct estructuraEscribir *punteroANodoNuevoEscribir=NULL;
	struct estructuraLeer *punteroANodoNuevoLeer=NULL;
	pthread_mutex_lock(&mutexArchConfig);
	socketServidor = socketInet_abrir (stConfig.puertoFSyPPD);
	pthread_mutex_unlock(&mutexArchConfig);
	//socketServidor = socketInet_abrir (7102);
	if (socketServidor == -1) {
		perror ("Error al abrir servidor");
		exit (-1);
	}
	while (1) {

		descriptoresCaidos_detectar (&punteroFteSelect,&punteroFinSelect);
		FD_ZERO (&conjuntoDeDescriptores);
		FD_SET (socketServidor, &conjuntoDeDescriptores);
		punteroAuxSelect=punteroFteSelect;
		while(punteroAuxSelect!=NULL) {
			FD_SET (punteroAuxSelect->descriptor, &conjuntoDeDescriptores);
			punteroAuxSelect=punteroAuxSelect->siguiente;
		}
		maximo = descriptorMaximo_detectar (&punteroFteSelect,&punteroFinSelect);
		if (maximo < socketServidor)
			maximo = socketServidor;
		select (maximo + 1, &conjuntoDeDescriptores, NULL, NULL, NULL);
		punteroAuxSelect=punteroFteSelect;

		while(punteroAuxSelect!=NULL) {
			if (FD_ISSET (punteroAuxSelect->descriptor, &conjuntoDeDescriptores)) {
				NIPC_recibir(&(punteroAuxSelect->descriptor),&punteroNIPCRecibir);
			if(punteroAuxSelect->descriptor!=-1){
				switch(punteroNIPCRecibir.type) {
					case '0':
						printf("Recibido: [type: %c]; ",punteroNIPCRecibir.type);
						printf("[payloadLength: %d]; ",punteroNIPCRecibir.payloadLength);
						printf("[payload: %s]; ",punteroNIPCRecibir.payload);
						printf("[numeroSector: %d]\n",punteroNIPCRecibir.numeroSector);
						//en cliente nuevo se manda el tipo (fs 1 y ppd 0)y el status(0 ok 1 down)
						//si el payload del handshake esta vacio,es un fs
						if(memcmp(punteroNIPCRecibir.payload,"id",strlen("id"))==0) {
							memcpy(punteroAuxSelect->identificadorPPD,punteroNIPCRecibir.payload,strlen(punteroNIPCRecibir.payload));
							punteroAuxSelect->tipo=0;
							if(maestro_estasConectado()==0)
								punteroAuxSelect->status=1;
							else
								{punteroAuxSelect->status=0;
								pthread_mutex_lock(&mutexDescriptorASincronizar);
								descriptorASincronizar=punteroAuxSelect->descriptor;
								pthread_mutex_unlock(&mutexDescriptorASincronizar);
								memset(identificadorPPDSincro,'\0',20);
								memcpy(identificadorPPDSincro,punteroNIPCRecibir.payload,strlen(punteroNIPCRecibir.payload));
								pthread_mutex_lock(&mutexSincro);
								sincronizador=1;
								pthread_mutex_unlock(&mutexSincro);

								}
							printf("Se ha conectado un nuevo PPD, cuyo identificador es: %s\n",punteroNIPCRecibir.payload);

						} else {
							punteroAuxSelect->tipo=1;
							punteroAuxSelect->status=0;
						}


						NIPC_enviar(punteroAuxSelect->descriptor,'0',strlen("hola aye"),"hola aye",0);

						//free(punteroNIPCRecibir->payload);
						//free(punteroNIPCRecibir);

						memset(&punteroNIPCRecibir,'\0',sizeof(struct nipc_protocol));
						//memset(punteroNIPCenviar,'\0',sizeof(struct nipc_protocol));

						break;
					case '1':
						nodoEscritura_crear(&punteroANodoNuevoEscribir,punteroNIPCRecibir.numeroSector,punteroNIPCRecibir.payload);
						colaEscritura_meter(&punteroFrenteEscribir,&punteroFinEscribir, &punteroANodoNuevoEscribir);
						//free(punteroNIPCRecibir->payload);
					//	free(punteroNIPCRecibir);
						break;
					case '2':

						nodoLectura_crear(&punteroANodoNuevoLeer,punteroNIPCRecibir.numeroSector, 0);
						colaLectura_meter(&punteroFrenteLeer,&punteroFinLeer, &punteroANodoNuevoLeer);
						punteroANodoNuevoLeer=NULL;
					//	sem_post (&mutex);
						break;
					case '3':
						descriptorElegido=fs_elegirAEnviar();
						NIPC_enviar(descriptorElegido,punteroNIPCRecibir.type,punteroNIPCRecibir.payloadLength,punteroNIPCRecibir.payload,punteroNIPCRecibir.numeroSector);
						pthread_mutex_lock(&mutexPtroBackup);
						nodoDeColaBackup_eliminar(&(punteroAuxSelect->punteroBackup),&(punteroAuxSelect->punteroBackupFin),punteroNIPCRecibir.numeroSector);
						pthread_mutex_unlock(&mutexPtroBackup);


						break;
					case 'T':
						sscanf (punteroNIPCRecibir.payload,"%d,%d,%d",&C,&H,&S);

						if(cabezal == 0){
							cabezal = H;
							cilindros = C;
							sectoresPorPista=S;
							pthread_mutex_lock(&mutexSecTot);
							sectoresTotales=C*H*S;
							pthread_mutex_unlock(&mutexSecTot);
						}else if (cabezal != H || cilindros != C || sectoresPorPista != S){
							printf("Los valores de CHS no son los mismos que el ppd maestro\n");
							close(punteroAuxSelect->descriptor);

						}
						printf("Sectores total del archivo %d\n",sectoresTotales);

						break;

					case '4':
						nodoEscritura_crear(&punteroANodoNuevoEscribir,punteroNIPCRecibir.numeroSector,punteroNIPCRecibir.payload);
						colaEscritura_meter(&punteroFrenteSincro,&punteroFinSincro, &punteroANodoNuevoEscribir);
					//	anterior=time(NULL);
						break;
					default:

						break;
				}
			}
				//memset(punteroNIPCRecibir,'\0	',sizeof(struct nipc_protocol));
				//free(punteroNIPCRecibir->payload);
				//free(punteroNIPCRecibir);

			}

		punteroAuxSelect=punteroAuxSelect->siguiente;
	}


	if (FD_ISSET (socketServidor, &conjuntoDeDescriptores)) {
		clienteNuevo_agregar (socketServidor, &punteroFteSelect,&punteroFinSelect);
	}

	}
	pthread_exit(NULL);
	return 1;

}

int32_t fs_elegirAEnviar() {
	punteroFileSystem=punteroFteSelect;
	while(punteroFileSystem!=NULL) {
		if(punteroFileSystem->tipo==1) {
			return punteroFileSystem->descriptor;
		} else {
			if(punteroFileSystem->siguiente==NULL) {
				punteroFileSystem=punteroFteSelect;
			} else {
				punteroFileSystem=punteroFileSystem->siguiente;
			}
		}
	}
}

int32_t maestro_estasConectado(){
	struct listaSelect *punteroAux=punteroFteSelect;

	while(punteroAux!=NULL) {
		if ((punteroAux->tipo == 0)&&(punteroAux->status==1)) {
			return 1;
		}else{
				punteroAux=punteroAux->siguiente;
			}
		}
	return 0;
}
